<template>
  <div ref="canvas"></div>
</template>

<script lang="ts" setup>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import Stats from "three/examples/jsm/libs/stats.module";
import {GUI} from "three/examples/jsm/libs/lil-gui.module.min.js";
import { ref, onMounted } from "vue";

// 画布
const canvas = ref<any>('');
// 场景
const scene = new THREE.Scene();
scene.overrideMaterial = new THREE.MeshDepthMaterial();
// 相机
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 50, 110);
camera.lookAt(scene.position);
camera.position.set(-50, 40, 50);
// 渲染器
const renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setClearColor(new THREE.Color(0x000000));
renderer.setSize(window.innerWidth, window.innerHeight);
// 性能统计
const stat = Stats();
// 相机控件
const orbitControl = new OrbitControls(camera, renderer.domElement);
// gui
const controls = {
  cameraNear: camera.near,
  cameraFar: camera.far,
  rotationSpeed: 0.01,
  numberOfObjects: scene.children.length,
  removeCube: () => {
    const children = scene.children;
    const lastObj = children[children.length - 1];
    if (lastObj instanceof THREE.Mesh) {
      scene.remove(lastObj as THREE.Object3D);
      controls.numberOfObjects = scene.children.length;
    }
  },
  addCube: () => {
    const cubeSize = Math.ceil(3 + (Math.random() * 3));
    const cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
    const cubeMaterial = new THREE.MeshLambertMaterial({
      color: Math.random() * 0xffffff
    });
    const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
    cube.castShadow = true;

    cube.position.x = -60 + Math.round((Math.random() * 100));
    cube.position.y = Math.round((Math.random() * 10));
    cube.position.z = -100 + Math.round((Math.random() * 150));

    scene.add(cube);
    controls.numberOfObjects = scene.children.length;
  },
};
const gui = new GUI();
const spGui = gui.addFolder("THREE.MeshDepthMaterial");
// @ts-ignore
spGui.add(scene.overrideMaterial, 'wireframe').name("骨架");
// @ts-ignore
spGui.add(scene.overrideMaterial, 'wireframeLinewidth', 0, 20).name("骨架线宽");
// @ts-ignore
gui.add(controls, 'rotationSpeed', 0, 0.5).name("旋转速度").step(0.01);
// @ts-ignore
gui.add(controls, 'addCube').name("添加正方体");
// @ts-ignore
gui.add(controls, 'removeCube').name("移除正方体");
// @ts-ignore
gui.add(controls, 'cameraNear', 0, 100).name("相机近视").onChange(function (e) {
  camera.near = e;
  camera.updateProjectionMatrix();
});
// @ts-ignore
gui.add(controls, 'cameraFar', 50, 200).name("相机远视").onChange(function (e) {
  camera.far = e;
  camera.updateProjectionMatrix();
});

let i = 0;
while (i < 10) {
  controls.addCube();
  i++;
}

const render = () => {
  stat.update();
  orbitControl.update();

  scene.traverse(function (e) {
    if (e instanceof THREE.Mesh) {
      e.rotation.x += controls.rotationSpeed;
      e.rotation.y += controls.rotationSpeed;
      e.rotation.z += controls.rotationSpeed;
    }
  });

  requestAnimationFrame(render);
  renderer.render(scene, camera);
};

onMounted(() => {
  canvas.value.appendChild(stat.domElement);
  canvas.value.appendChild(renderer.domElement);

  render();
});
</script>